mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
Unify pool score display as account health
This commit is contained in:
@@ -6,6 +6,7 @@ use crate::handlers::admin::shared::{provider_key_status_snapshot_payload, unix_
|
||||
use crate::provider_key_auth::{provider_key_auth_semantics, provider_key_effective_api_formats};
|
||||
use aether_admin::provider::pool as admin_provider_pool_pure;
|
||||
use aether_admin::provider::quota as admin_provider_quota_pure;
|
||||
use aether_data_contracts::repository::pool_scores::StoredPoolMemberScore;
|
||||
use aether_data_contracts::repository::provider_catalog::{
|
||||
StoredProviderCatalogEndpoint, StoredProviderCatalogKey,
|
||||
};
|
||||
@@ -906,6 +907,7 @@ pub(super) fn build_admin_pool_key_payload(
|
||||
key: &StoredProviderCatalogKey,
|
||||
runtime: &AdminProviderPoolRuntimeState,
|
||||
pool_config: Option<AdminProviderPoolConfig>,
|
||||
pool_score: Option<&StoredPoolMemberScore>,
|
||||
codex_cycle_usage_by_code: Option<&BTreeMap<String, StoredProviderApiKeyWindowUsageSummary>>,
|
||||
now_unix_secs: u64,
|
||||
) -> serde_json::Value {
|
||||
@@ -1087,6 +1089,34 @@ pub(super) fn build_admin_pool_key_payload(
|
||||
payload.insert("status_snapshot".to_string(), status_snapshot);
|
||||
payload.insert("quota_updated_at".to_string(), json!(quota_updated_at));
|
||||
payload.insert("health_score".to_string(), json!(health_score));
|
||||
payload.insert(
|
||||
"pool_score".to_string(),
|
||||
pool_score
|
||||
.map(|score| {
|
||||
json!({
|
||||
"id": score.id.clone(),
|
||||
"capability": score.capability.clone(),
|
||||
"scope_kind": score.scope_kind.clone(),
|
||||
"scope_id": score.scope_id.clone(),
|
||||
"score": score.score,
|
||||
"hard_state": score.hard_state.as_database(),
|
||||
"score_version": score.score_version,
|
||||
"score_reason": score.score_reason.clone(),
|
||||
"last_ranked_at": score.last_ranked_at,
|
||||
"last_scheduled_at": score.last_scheduled_at,
|
||||
"last_success_at": score.last_success_at,
|
||||
"last_failure_at": score.last_failure_at,
|
||||
"failure_count": score.failure_count,
|
||||
"last_probe_attempt_at": score.last_probe_attempt_at,
|
||||
"last_probe_success_at": score.last_probe_success_at,
|
||||
"last_probe_failure_at": score.last_probe_failure_at,
|
||||
"probe_failure_count": score.probe_failure_count,
|
||||
"probe_status": score.probe_status.as_database(),
|
||||
"updated_at": score.updated_at,
|
||||
})
|
||||
})
|
||||
.unwrap_or(serde_json::Value::Null),
|
||||
);
|
||||
payload.insert(
|
||||
"circuit_breaker_open".to_string(),
|
||||
json!(circuit_breaker_open),
|
||||
|
||||
@@ -7,9 +7,13 @@ use super::{
|
||||
AdminPoolKeySortField, AdminProviderPoolRuntimeState, ProviderCatalogKeyListOrder,
|
||||
ProviderCatalogKeyListQuery, ADMIN_POOL_PROVIDER_CATALOG_READER_UNAVAILABLE_DETAIL,
|
||||
};
|
||||
use crate::ai_serving::{provider_key_pool_score_id, provider_key_pool_score_scope};
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
use crate::GatewayError;
|
||||
use aether_admin::provider::pool as admin_provider_pool_pure;
|
||||
use aether_data_contracts::repository::pool_scores::{
|
||||
GetPoolMemberScoresByIdsQuery, PoolMemberIdentity, StoredPoolMemberScore,
|
||||
};
|
||||
use aether_data_contracts::repository::provider_catalog::StoredProviderCatalogKey;
|
||||
use aether_data_contracts::repository::usage::{
|
||||
ProviderApiKeyWindowUsageRequest, StoredProviderApiKeyWindowUsageSummary,
|
||||
@@ -56,6 +60,36 @@ fn admin_pool_current_unix_secs() -> u64 {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
async fn read_admin_pool_scores_by_key_id(
|
||||
state: &AdminAppState<'_>,
|
||||
provider_id: &str,
|
||||
key_ids: &[String],
|
||||
) -> Result<BTreeMap<String, StoredPoolMemberScore>, GatewayError> {
|
||||
if key_ids.is_empty() {
|
||||
return Ok(BTreeMap::new());
|
||||
}
|
||||
|
||||
let score_scope = provider_key_pool_score_scope();
|
||||
let score_ids = key_ids
|
||||
.iter()
|
||||
.map(|key_id| {
|
||||
let identity =
|
||||
PoolMemberIdentity::provider_api_key(provider_id.to_string(), key_id.clone());
|
||||
provider_key_pool_score_id(&identity, &score_scope)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let scores = state
|
||||
.app()
|
||||
.data
|
||||
.get_pool_member_scores_by_ids(&GetPoolMemberScoresByIdsQuery { ids: score_ids })
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(format!("{err:?}")))?;
|
||||
Ok(scores
|
||||
.into_iter()
|
||||
.map(|score| (score.member_id.clone(), score))
|
||||
.collect::<BTreeMap<_, _>>())
|
||||
}
|
||||
|
||||
fn admin_pool_codex_cycle_usage_request(
|
||||
key: &StoredProviderCatalogKey,
|
||||
window: &serde_json::Map<String, serde_json::Value>,
|
||||
@@ -379,6 +413,9 @@ pub(super) async fn build_admin_pool_list_keys_response(
|
||||
};
|
||||
|
||||
let key_ids = keys.iter().map(|key| key.id.clone()).collect::<Vec<_>>();
|
||||
let pool_scores_by_key_id = read_admin_pool_scores_by_key_id(state, &provider.id, &key_ids)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
let endpoints = state
|
||||
.list_provider_catalog_endpoints_by_provider_ids(std::slice::from_ref(&provider.id))
|
||||
.await?;
|
||||
@@ -414,6 +451,7 @@ pub(super) async fn build_admin_pool_list_keys_response(
|
||||
&key,
|
||||
&runtime,
|
||||
pool_config.clone(),
|
||||
pool_scores_by_key_id.get(&key.id),
|
||||
codex_cycle_usage_by_key.get(&key.id),
|
||||
now_unix_secs,
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::handlers::shared::query_param_value;
|
||||
use crate::GatewayError;
|
||||
use aether_data_contracts::repository::pool_scores::{
|
||||
ListPoolMemberScoresQuery, PoolMemberHardState, PoolMemberProbeStatus,
|
||||
POOL_KIND_PROVIDER_KEY_POOL, POOL_SCORE_SCOPE_KIND_MODEL,
|
||||
POOL_KIND_PROVIDER_KEY_POOL, POOL_SCORE_CAPABILITY_ACCOUNT, POOL_SCORE_SCOPE_KIND_ACCOUNT,
|
||||
};
|
||||
use axum::{
|
||||
body::Body,
|
||||
@@ -49,9 +49,6 @@ pub(super) async fn build_admin_pool_scores_response(
|
||||
}
|
||||
};
|
||||
let offset = page.saturating_sub(1).saturating_mul(page_size);
|
||||
let api_format = query_param_value(query, "api_format")
|
||||
.map(|value| crate::ai_serving::normalize_api_format_alias(value.as_str()));
|
||||
let model_id = query_param_value(query, "model_id");
|
||||
let hard_states = match parse_hard_state_filter(query) {
|
||||
Ok(value) => value,
|
||||
Err(message) => {
|
||||
@@ -77,9 +74,9 @@ pub(super) async fn build_admin_pool_scores_response(
|
||||
.list_pool_member_scores(&ListPoolMemberScoresQuery {
|
||||
pool_kind: POOL_KIND_PROVIDER_KEY_POOL.to_string(),
|
||||
pool_id: provider_id.clone(),
|
||||
capability: api_format.clone(),
|
||||
scope_kind: Some(POOL_SCORE_SCOPE_KIND_MODEL.to_string()),
|
||||
scope_id: model_id.clone(),
|
||||
capability: Some(POOL_SCORE_CAPABILITY_ACCOUNT.to_string()),
|
||||
scope_kind: Some(POOL_SCORE_SCOPE_KIND_ACCOUNT.to_string()),
|
||||
scope_id: None,
|
||||
hard_states,
|
||||
probe_statuses,
|
||||
offset,
|
||||
@@ -146,8 +143,8 @@ pub(super) async fn build_admin_pool_scores_response(
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
"filters": {
|
||||
"api_format": api_format,
|
||||
"model_id": model_id,
|
||||
"api_format": serde_json::Value::Null,
|
||||
"model_id": serde_json::Value::Null,
|
||||
"hard_state": query_param_value(query, "hard_state"),
|
||||
"probe_status": query_param_value(query, "probe_status")
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user